'use strict';

module.exports = core;

const path = require('path');

const semver = require('semver');
const colors = require('colors/safe');
const userHome = require('user-home');
const commander = require('commander');

// require 可以解析 .js .json .node 其它后缀自动识别为 .js 文件解析
const pkg = require('../package.json');
const log = require('@nz-cli/log');
const exec = require('@nz-cli/exec');

const constant = require('./const');

let pathExists;

// 实例化一个脚手架命令对象
const program = new commander.Command();

async function core() {
  try {
    await prepare();
    registerCommand();
  } catch (e) {
    log.error(e.message);
    if (program['_optionValues'].debug) {
      console.log(e);
    }
  }
}

// 注册脚手架命令
function registerCommand() {
  program
    .name(Object.keys(pkg.bin)[0])
    .usage('<command> [options]')
    .version(pkg.version)
    .option('-d, --debug', '是否开启调试模式', false)
    .option('--tp, --targetPath <targetPath>', '是否指定本地调试文件路径', '')

  program
    .command('init [projectName]')
    // 清空当前目录下的文件后，进行初始化
    .option('-f, --force', '是否强制初始化')
    .action(exec)
  
  program.on('option:debug', () => {
    // 检查入参，判断是否进入 debug 模式，需要打印 debug 日志
    if (program['_optionValues'].debug) {
      process.env.LOG_LEVEL = 'verbose';
    } else {
      process.env.LOG_LEVEL = 'info';
    }
    log.level = process.env.LOG_LEVEL;
  });

  program.on('option:targetPath', () => {
    // 通过环境变量挂载数据，实现和业务逻辑解耦，在init之前执行
    process.env.CLI_TARGET_PATH = program['_optionValues'].targetPath;
  })

  // 监听未知命令
  program.on('command:*', (obj) => {
    const availableCommands = program.commands.map(cmd => cmd.name());
    console.log(colors.red('未知命令: ' + obj[0]));
    if (availableCommands.length > 0) {
      console.log(colors.red('可用命令: ' + availableCommands.join(',')));
    }
  });

  program.parse(process.argv);
  // 没执行实际命令的时候，打印出帮助文档
  if (program.args && program.args.length < 1) {
    // 空行隔开
    console.log();
    program.outputHelp();
    console.log();
  }
}

async function prepare () {
  checkPkgVersion();
  await checkRoot();
  await chekcUserHome();
  checkEnv();
  await checkGlobalUpdate();
}

// 提示更新最新版本
async function checkGlobalUpdate() {
  const currentVersion = pkg.version;
  const npmName = pkg.name;
  const { getNpmSemverVersion } = require('@nz-cli/get-npm-info');
  const lastVersion = await getNpmSemverVersion(currentVersion, npmName);
  if (lastVersion && semver.gt(lastVersion, currentVersion)) {
    log.warn(colors.yellow(`请手动更新 ${npmName}, 当前版本：${currentVersion} ，最新版本：${lastVersion}
        更新命令： npm install -g ${npmName}`));
  }
}

// 检查环境变量 - 将用户名密码等敏感信息保存在用户本地，而不用集成到代码中
function checkEnv() {
  const dotenv = require('dotenv');
  const dotenvPath = path.resolve(userHome, '.env');
  if (pathExists(dotenvPath)) {
    dotenv.config({
      path: dotenvPath
    });
  }
  createDefaultConfig();
}

function createDefaultConfig() {
  const cliConfig = {
    home: userHome
  }
  if (process.env.CLI_HOME) {
    cliConfig['cliHome'] = path.join(userHome, process.env.CLI_HOME);
  } else {
    cliConfig['cliHome'] = path.join(userHome, constant.DEFAULT_CLI_HOME);
  }
  process.env.CLI_HOME_PATH = cliConfig.cliHome;
}

// 跨操作系统获取用户主目录
async function chekcUserHome() {
  const pathExistsObj = await import('path-exists');
  pathExists = pathExistsObj.pathExistsSync;
  if (!userHome || !pathExists(userHome)) {
    throw new Error(colors.red('当前登录用户的主目录不存在！'));
  }
}

// 检查用户权限，并降低进程的用户权限
async function checkRoot() {
  // macOS 上降低 进程的 用户权限的，windows上不能用，实现的机制不一样
  // window 上通过 非管理员 的帐户进行操作就行
  const rootCheck = await import('root-check');
  rootCheck.default();
}

function checkPkgVersion() {
  log.notice('cli', pkg.version);
}
